###   导入包   ###
import pyhandylang.Ast as AST
from pyhandylang.Lexer import Lexer

###   总打印次数   ###
printPNum = 0
###   是否打印详细信息   ###
ParserDebug = False


###   定义打印   ###
def printP(op, p):
    global printPNum;
    printPNum = printPNum + 1
    if ParserDebug == False: return
    print('-----step=%d-----op=\'%s\'-----' % (printPNum, op))
    for i in range(len(p)):
        print('op=\'%s\'---pos=\'%d\'---val=\'%s\'' % (op, i, p[i]))


###   定义语法解析类   ###
class Parser(object):
    ###   全局token，静态变量   ###
    tokens = Lexer.tokens
    ###   操作符优先级定义，静态变量   ###
    precedence = (
        # 无结合性操作符
        ('nonassoc', 'LT', 'GT', 'LTE', 'GTE'),
        # 左结合性操作符
        # 先执行加法，所以加法在减法下面
        ('left', 'MINUS'),
        ('left', 'PLUS'),
        # 先执行乘法，所以乘法在除法下面
        ('left', 'DIVIDE'),
        ('left', 'TIMES'),
        ('left', 'MOD'),
        # 逻辑操作
        ('left', 'AND'),
        ('left', 'OR'),
        ('left', 'EQ'),
        ('left', 'NEQ'),
        # 右结合性操作符
        ('right', 'UMINUS'),
    )

    ###   24.程序模块定义   ###
    def p_stmt_list(p):
        """stmt_list : stmt_list stmt
                    | stmt
        """
        if len(p) == 2:
            p[0] = AST.StatementList()
            p[0].add_statement(p[1])
        else:
            p[1].add_statement(p[2])
            p[0] = p[1]
        printP('p_stmt_list', p)

    def p_stmt_func_def(p):
        """
        stmt : FUNCTION NAME LPAREN RPAREN stmt_suite
             | FUNCTION NAME LPAREN NAME RPAREN stmt_suite
             | FUNCTION NAME LPAREN param_suite RPAREN stmt_suite
        """
        if len(p) == 6:
            p[0] = AST.FunctionDefine(p[2], p[5], p[2])
        elif len(p) == 7:
            if isinstance(p[4], AST.ParamList):
                p[0] = AST.FunctionDefine(p[2], p[6], p[2], p[4])
            else:
                p[0] = AST.FunctionDefine(p[2], p[6], p[2], AST.ParamList(p[4]))
        elif len(p) == 9:
            p[0] = AST.FunctionDefine(p[2], p[8], p[2], [p[4], p[6]])
        else:
            raise Exception

    def p_stmt_return(p):
        """stmt : RETURN expr
                """
        if len(p) == 2:
            p[0] = AST.Return(None, vars=[])
        else:
            p[0] = AST.Return(None, vars=[p[2]])

    ###   23.FOR定义   ###
    def p_stmt_for(p):
        """stmt : FOR expr COLON stmt_suite
                | FOR NAME ASSIGN INT COLON INT stmt_suite
                | FOR NAME ASSIGN INT COLON INT COLON INT stmt_suite
        """
        if len(p) == 5:
            p[0] = AST.For(p[2], p[4])
        elif len(p) == 8:
            p[0] = AST.For(p[2], p[7], tmpIdentifier=p[2], start=p[4], end=p[6])
        else:
            p[0] = AST.For(p[2], p[9], tmpIdentifier=p[2], start=p[4], end=p[8], step=p[6])

            pass
        printP('p_stmt_for', p)

    ###   23.WHILE定义   ###
    def p_stmt_while(p):
        """stmt : WHILE expr stmt_suite
                | WHILE expr stmt_suite ELSE stmt_suite
        """
        if len(p) == 4:
            p[0] = AST.While(p[2], p[3], None)
        else:
            p[0] = AST.While(p[2], p[3], p[5])
        printP('p_stmt_while', p)

    ###   22.IF定义   ###
    def p_stmt_if(p):
        """stmt : IF expr stmt_suite
                    | IF expr stmt_suite ELSE stmt_suite
        """
        if len(p) == 4:
            p[0] = AST.If(p[2], p[3], None)
        else:
            p[0] = AST.If(p[2], p[3], p[5])
        printP('p_stmt_if', p)

    ###   21.程序{}定义   ###
    def p_suite(p):
        """stmt_suite : LBRACK stmt_list RBRACK"""
        p[0] = p[2]
        printP('p_suite', p)

    def p_expr_paramsuite(p):
        """param_suite : NAME COMMA NAME
                       | NAME COMMA param_suite"""
        p[0] = AST.ParamList(p[1], p[3])

    ### 用逗号分隔的expr_suite定义
    def p_expr_suite(p):
        """expr_suite : expr COMMA expr
                      | expr COMMA expr_suite
                      """
        p[0] = AST.ExprList(p[1], p[3])

    ################################################
    ###   20.打印   ###
    def p_expr_print_expr(p):
        """stmt : PRINT LPAREN expr RPAREN"""
        p[0] = AST.Print(p[3])
        printP('p_expr_print_expr', p)

    def p_func_call(p):
        """expr : NAME LPAREN expr_suite RPAREN
                | NAME LPAREN expr RPAREN
                | NAME LPAREN RPAREN
           stmt : NAME LPAREN RPAREN
                | NAME LPAREN expr RPAREN
                | NAME LPAREN expr_suite RPAREN
                """
        if len(p) == 4:
            p[0] = AST.FunctionCall(name=p[1])
        if len(p) == 5:
            if isinstance(p[3], AST.ExprList):
                p[0] = AST.FunctionCall(name=p[1], arguments=[p[3]], body=p[3])
            else:
                p[0] = AST.FunctionCall(name=p[1], arguments=[p[3]], body=p[3])
        # elif len(p) == 7:
        #     p[0] = AST.FunctionCall(name=p[1], arguments=[p[3], p[5]])

    ###   19.变量或者函数等转换   ###
    def p_expr_name(p):
        """expr : NAME"""
        p[0] = AST.Name(p[1])
        printP('p_expr_name', p)

    ###   18.赋值   ###
    def p_expr_assign(p):
        """stmt : NAME ASSIGN expr"""
        p[0] = AST.Assign(p[1], p[3])
        printP('p_expr_assign', p)

    ###   17.括号   ###
    def p_expr_group(p):
        """expr : LPAREN expr RPAREN"""
        p[0] = p[2]
        printP('p_expr_group', p)

    ###   16.or   ###
    def p_expr_or(p):
        """expr : expr OR expr"""
        p[0] = AST.BoolOpOr(p[1], p[3])
        printP('p_expr_or', p)

    ###   15.and   ###xxx
    def p_expr_and(p):
        """expr : expr AND expr"""
        p[0] = AST.BoolOpAnd(p[1], p[3])
        printP('p_expr_and', p)

    ###   14.!=   ###
    def p_expr_neq(p):
        """expr : expr EQ expr"""
        p[0] = AST.CompareOpNeq(p[1], p[3])
        printP('p_expr_neq', p)

    ###   14.==   ###
    def p_expr_eq(p):
        """expr : expr NEQ expr"""
        p[0] = AST.CompareOpEq(p[1], p[3])
        printP('p_expr_eq', p)

    ###   14.<=   ###
    def p_expr_lte(p):
        """expr : expr LTE expr"""
        p[0] = AST.CompareOpLte(p[1], p[3])
        printP('p_expr_lte', p)

    ###   13.<   ###
    def p_expr_lt(p):
        """expr : expr LT expr"""
        p[0] = AST.CompareOpLt(p[1], p[3])
        printP('p_expr_lt', p)

    ###   12.>=   ###
    def p_expr_gte(p):
        """expr : expr GTE expr"""
        p[0] = AST.CompareOpGte(p[1], p[3])
        printP('p_expr_gte', p)

    ###   11.>   ###
    def p_expr_gt(p):
        """expr : expr GT expr"""
        p[0] = AST.CompareOpGt(p[1], p[3])
        printP('p_expr_gt', p)

    ###   10.负号   ###
    def p_expr_uminus(p):
        """expr : MINUS expr %prec UMINUS"""
        p[0] = AST.BinOpTimes(AST.Number(-1), p[2])
        printP('p_expr_uminus', p)

    ###   9.取模  ###
    def p_expr_mod(p):
        """expr : expr MOD expr"""
        p[0] = AST.BinOpMod(p[1], p[3])
        printP('p_expr_mod', p)

    ###   8.除法  ###
    def p_expr_divide(p):
        """expr : expr DIVIDE expr"""
        p[0] = AST.BinOpDivde(p[1], p[3])
        printP('p_expr_divide', p)

    ###   7.乘法  ###
    def p_expr_times(p):
        """expr : expr TIMES expr"""
        p[0] = AST.BinOpTimes(p[1], p[3])
        printP('p_expr_times', p)

    ###   6.减法  ###
    def p_expr_minus(p):
        """expr : expr MINUS expr"""
        p[0] = AST.BinOpMinus(p[1], p[3])
        printP('p_expr_minus', p)

    ###   5.加法  ###
    def p_expr_plus(p):
        """expr : expr PLUS expr
        """
        p[0] = AST.BinOpPlus(p[1], p[3])
        printP('p_expr_plus', p)

    ###   4.STRING转表达式   ###
    def p_expr_string(p):
        """expr : STRING"""
        # 构建AST
        p[0] = AST.Str(p[1])
        printP('p_expr_string', p)

    ###   3.CONST转表达式   ###
    def p_expr_const(p):
        """expr : TRUE
                | FALSE
                | NONE
        """
        p[0] = AST.Const(p[1])
        printP('p_expr_const', p)

    ###   2.FLOAT转表达式   ###
    def p_expr_float(p):
        """expr : FLOAT"""
        # 构建AST
        p[0] = AST.Number(p[1])
        printP('p_expr_float', p)

    ###   1.INT转表达式   ###
    def p_expr_int(p):
        """expr : INT"""
        # 构建AST
        p[0] = AST.Number(p[1])
        printP('p_expr_int', p)

    ###   异常函数   ###
    def p_error(p):
        if p:
            print("Parser error = value  = '%s', type = '%s', lineno = '%d'" % (p.value, p.type, p.lineno))
        else:
            print("Syntax error at EOF")
